package com.neusoft.bizcore.web.support;

import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import com.neusoft.bizcore.web.utils.WebUtils;

import lombok.extern.slf4j.Slf4j;

/**
 * be used to resolve the {@Searchable} parameters.
 *
 * @author sunchf
 * @date 2018年12月6日 下午2:46:01
 */
@Slf4j
public class SearchableArgumentResolver implements HandlerMethodArgumentResolver {

    private static final String SEARCHABLE_PREFIX = "s_";
    private static final String OPERATOR_SPLIT = "\\|";
    private static final String ARRAY_SPLIT = ",";

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return Searchable.class.equals(parameter.getParameterType());
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
            NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        final Searchable searchable = new Searchable();

        webRequest.getParameterNames().forEachRemaining(paramName -> {
            if (paramName.startsWith(SearchableArgumentResolver.SEARCHABLE_PREFIX)) {
                final String[] values = webRequest.getParameterValues(paramName);
                if (values.length == 1) {
                    String value = values[0];
                    if (WebUtils.hasUrlEncoded(value)) {
                        value = WebUtils.decodeURI(value);
                    }

                    final String[] valAndOperator = value.split(SearchableArgumentResolver.OPERATOR_SPLIT);
                    QueryOperator operator = QueryOperator.none;
                    if (valAndOperator.length > 1) {
                        try {
                            operator = QueryOperator.valueOf(valAndOperator[1]);
                        } catch (final IllegalArgumentException e) {
                            SearchableArgumentResolver.log.warn("暂不支持操作符 {}", valAndOperator[1]);
                        }
                    }
                    final String[] arrays = valAndOperator[0].split(SearchableArgumentResolver.ARRAY_SPLIT);

                    if (arrays.length == 1) {
                        searchable.put(this.getQueryKey(paramName), arrays[0], operator);

                    } else {
                        searchable.put(this.getQueryKey(paramName), arrays, operator);
                    }
                } else {
                    for (int i = 0; i < values.length; i++) {
                        if (WebUtils.hasUrlEncoded(values[i])) {
                            values[i] = WebUtils.decodeURI(values[i]);
                        }
                    }
                    searchable.put(this.getQueryKey(paramName), values, QueryOperator.none);
                }
            }
        });
        return searchable;
    }

    private String getQueryKey(String withPrefix) {
        return withPrefix.substring(SearchableArgumentResolver.SEARCHABLE_PREFIX.length());
    }
}
